/*******************************************************************************
 * @file                   stepper.c
 * @Author:                MQjehovah                 mail:MQjehovah@hotmail.com
 * @version                1.0.0
 * @date                   2018/01/23
 * @brief                  42步进电机 转矩0.5N·M 步距角1.8°
 ******************************************************************************
 * @attention
*******************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include "stepper.h"
#include "shell.h"
/* Definition ----------------------------------------------------------------*/
STEPPER stepper = {0};
/* Functions -----------------------------------------------------------------*/
/*******************************************************************************
  * @brief  步进电机IO口初始化              
  * @param  None                   
  * @retval None                   
  * @Note   None                   
*******************************************************************************/
void stepper_gpio_init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB, ENABLE); //使能PORTA PORTB时钟
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;                                    //PB4-EN
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;                                //普通输出模式
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;                               //推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;                           //100MHz
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;                                 //上拉
    GPIO_Init(GPIOB, &GPIO_InitStructure);                                       //初始化
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;                                    //PB3-PUL
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;                              //复用功能(如果是采用定时器PWM输出需要配制成AF模式)
    GPIO_Init(GPIOB, &GPIO_InitStructure);     //初始化PB3
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //PA10-DIR
    GPIO_Init(GPIOA, &GPIO_InitStructure);
}

/*******************************************************************************
  * @brief  通用定时器中断初始化              
  * @param  arr：自动重装值。    psc：时钟预分频数                   
  * @retval None                   
  * @Note   定时器溢出时间计算方法:Tout=((arr+1)*(psc+1))/Ft us.   
            Ft=定时器工作频率,单位:Mhz   84M        
            定时器3，用来计时控制步进电机加减速周期       
*******************************************************************************/
void stepper_tim_init(u16 arr, u16 psc)
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    stepper_gpio_init();
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); ///使能TIM3时钟

    TIM_DeInit(TIM3);
    TIM_TimeBaseInitStructure.TIM_Period = arr - 1;                 //自动重装载值100ms
    TIM_TimeBaseInitStructure.TIM_Prescaler = psc - 1;              //定时器分频8400
    TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式
    TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure); //初始化TIM3
    TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);          //允许定时器3更新中断

    NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;              //定时器3中断
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级1
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03;        //子优先级3
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    TIM_Cmd(TIM3, ENABLE); //使能定时器3
}

/*******************************************************************************
  * @brief  定时器PWM输出初始化              
  * @param  arr：自动重装值。    psc：时钟预分频数                     
  * @retval None                   
  * @Note   None                   
*******************************************************************************/
void stepper_pwm_init(u16 arr, u16 psc)
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_OCInitTypeDef TIM_OCInitStructure;
    stepper_gpio_init();
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);    //TIM2时钟使能
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource3, GPIO_AF_TIM2); //GPIOB3复用为定时器2

    TIM_TimeBaseStructure.TIM_Prescaler = psc - 1;              //定时器分频
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式
    TIM_TimeBaseStructure.TIM_Period = arr - 1;                 //自动重装载值
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //初始化定时器2

    //初始化TIM2 Channel2 PWM模式
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式2
    TIM_OCInitStructure.TIM_Pulse = (arr - 1) >> 1;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
    // TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable; //高级定时器互补输出
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性低
    TIM_OC2Init(TIM2, &TIM_OCInitStructure);                  //根据T指定的参数初始化外设

    TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable); //使能TIM2在CCR2上的预装载寄存器
    TIM_ARRPreloadConfig(TIM2, ENABLE);               //ARPE使能
    TIM_CCPreloadControl(TIM2, ENABLE);
    TIM_CtrlPWMOutputs(TIM2, ENABLE);
    TIM_Cmd(TIM2, ENABLE); //使能TIM2
}

/*******************************************************************************
  * @brief  设置步进电机使能              
  * @param  None                   
  * @retval None                   
  * @Note   None                   
*******************************************************************************/
void stepper_set_enable(u8 value)
{
    if (value)
        GPIO_ResetBits(GPIOB, GPIO_Pin_4);
    else
        GPIO_SetBits(GPIOB, GPIO_Pin_4);
    stepper.en = value;
}

/*******************************************************************************
  * @brief  设置步进电机方向          
  * @param  None                   
  * @retval None                   
  * @Note   None                   
*******************************************************************************/
void stepper_set_dir(u8 value)
{
    if (value)
        GPIO_ResetBits(GPIOA, GPIO_Pin_10);
    else
        GPIO_SetBits(GPIOA, GPIO_Pin_10);
    stepper.dir = value;
}

char flag = 0;
/*******************************************************************************
  * @brief  定时器3中断服务函数              
  * @param  None                   
  * @retval None                   
  * @Note   None                   
*******************************************************************************/
void TIM3_IRQHandler(void)
{
    if (TIM_GetITStatus(TIM3, TIM_IT_Update) == SET) //溢出中断
    {
        if (stepper.step > 0)
        {
            if (flag)
            {
                flag = 0;
                stepper.step--;
                GPIO_SetBits(GPIOB, GPIO_Pin_3);
            }
            else
            {
                flag++;
                GPIO_ResetBits(GPIOB, GPIO_Pin_3);
            }
        }
    }
    TIM_ClearITPendingBit(TIM3, TIM_IT_Update); //清除中断标志位
}
/*********************************END OF FILE**********************************/
